#include "log.hpp"
#include "Socket.hpp"
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>

const uint16_t default_port = 8080;
const std::string sep = "\r\n";
const std::string file_path = "./wwwroot";
const std::string homepage = "index.html";

class Request
{
public:
    void Deserizlize(std::string req)
    {
        while (true) 
        {
            size_t pos = req.find(sep);
            if(pos == std::string::npos) break;
            std::string tmp = req.substr(0, pos);
            if (tmp.empty()) break;
            req_header.push_back(move(tmp));
            req.erase(0, pos + sep.size());
        }
        text = move(req);
    }
    void Parse()
    {
        std::stringstream ss(req_header[0]);
        ss >> method >> url >> http_version;

        path = file_path;  // /wwwroot
        if (url == "/" || url == "/index.html")
            path += "/" + homepage;  // /wwwroot/index.html
        else
            path += url;  // /wwwroot + / + url
        
        auto pos = path.rfind(".");
        if(pos == std::string::npos) suffix = ".html";
        else suffix = path.substr(pos);

        DebugPrint();
    }
    void DebugPrint()
    {
        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "suffix: " << suffix << std::endl;
        std::cout << "path: " << path << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "text: \n" << text << std::endl; 
    }
public:
    // 解析前的结果
    std::vector<std::string> req_header;
    std::string text;
    // 解析后的结果
    std::string method;
    std::string url;
    std::string http_version;
    std::string path;
    std::string suffix;
};

class HttpServer;
class ThreadData
{
public:
    ThreadData(int sockfd, HttpServer *httpsvr) :sockfd_(sockfd), httpsvr_(httpsvr)
    {}
public:
    int sockfd_;
    HttpServer *httpsvr_;
};

class HttpServer
{
public:
    HttpServer(const uint16_t port = default_port) :port_(port)
    {
        content_type.insert({".html", "text/html"});
        content_type.insert({".png", "image/png"});
    }
    ~HttpServer() {}
public:
    void Start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        LOG(Info, "Listensock create success");

        for(;;)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            if (sockfd < 0) continue;
            LOG(Info, "get a new link, sockfd: %d", sockfd);
            pthread_t tid;
            ThreadData *td = new ThreadData(sockfd, this);
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }
    static void *ThreadRun(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData*>(args);
        td->httpsvr_->HandlerHttp(td->sockfd_);
        delete td;
        return nullptr;
    }
    void HandlerHttp(int sockfd)
    {
        char buffer[10240];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0) {
            buffer[n] = 0;
            std::cout << "recv: " << buffer << std::endl;

            Request req;
            req.Deserizlize(buffer);
            req.Parse();

            // 返回响应的过程
            std::string text;
            bool ok = true;
            text = move(ReadHtmlContent(req.path));
            if (text.empty()) {
                ok = false;
                std::string err_html = file_path;
                err_html += "/";
                err_html += "err.html";
                text = move(ReadHtmlContent(err_html));
            }

            std::string response_line;
            if (ok) response_line = "HTTP/1.0 200 OK\r\n";
            else response_line = "HTTP/1.0 404 Not Found\r\n";

            std::string response_header = "Content-Length: ";
            response_header += std::to_string(text.size());
            response_header += "\r\n";
            response_header += "Content-Type: ";
            response_header += move(SuffixToDesc(req.suffix));
            response_header += "\r\n";
            response_header += "Set-Cookie: name=haha";
            response_header += "\r\n";

            std::string blank_line = "\r\n";
            std::string response(move(response_line));
            response += move(response_header);
            response += move(blank_line);
            response += move(text);            

            std::cout << "send:\n" << response << std::endl;
            send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd);
    }
    std::string ReadHtmlContent(const std::string& html_path)
    {
        // 以二进制读取方式打开文件
        std::ifstream in(html_path, std::ios::binary);
        if (!in.is_open()) return "";
        // 计算文件内容大小
        in.seekg(0, std::ios_base::end);
        auto len = in.tellg();
        in.seekg(0, std::ios_base::beg);
        // 读取文件内容
        std::string content;
        content.resize(len);
        in.read((char*)content.c_str(), len);
        
        in.close();
        return content;
    }
    std::string SuffixToDesc(const std::string &suffix)
    {
        auto iter = content_type.find(suffix);
        if (iter == content_type.end()) return content_type[".html"];
        else return content_type[suffix];
    }

public:
    uint16_t port_;
    Sock listensock_;
    std::unordered_map<std::string, std::string> content_type;
};